package com.snowyee.snowyeecodesandbox.utils;

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.StrUtil;
import com.snowyee.snowyeecodesandbox.model.ExecuteMessage;
import com.sun.management.OperatingSystemMXBean;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;


/**
 * 进程工具类
 */
public class ProcessUtils {
    private static final long TIME_OUT = 5000L; // 默认超时时间

    /**
     * 执行获取进程信息（args输入版本）
     * @param runCmd
     * @param opName
     * @return
     */
    public static ExecuteMessage getProcessMessage(String runCmd,String opName) {
        ExecuteMessage executeMessage = new ExecuteMessage();
        StopWatch stopWatch = new StopWatch();
        // 收集运行指令后的信息
        try {
            stopWatch.start();
            Runtime runtime = Runtime.getRuntime();
            Process runProcess = runtime.exec(runCmd);


            // 开启新线程监控程序运行线程，超时直接杀掉线程
            new Thread(() -> {
                try {
                    Thread.sleep(TIME_OUT);
                    runProcess.destroy();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

            // 指令正常执行，获取错误码
            int exitValue = runProcess.waitFor();
            executeMessage.setExitValue(exitValue);
            // 正常退出
            if (exitValue == 0){
                System.out.println(opName+"成功");

                // 分批获取进程的输出
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
                List<String> outputStrList = new ArrayList<>();
                // 逐行获取
                String compileOutputLine;
                while((compileOutputLine = bufferedReader.readLine()) != null){
                    outputStrList.add(compileOutputLine);
                }
                executeMessage.setMessage(StringUtils.join(outputStrList,"\n"));
            }else {
                System.out.println(opName+"失败, 错误码" + exitValue);
                // 分批获取进程的输出
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
                List<String> outputStrList = new ArrayList<>();
                // 逐行获取
                String compileOutputLine;
                while((compileOutputLine = bufferedReader.readLine()) != null){
                    outputStrList.add(compileOutputLine);
                }
                executeMessage.setMessage(StringUtils.join(outputStrList,"\n"));
                // 分批获取进程的错误输出
                // 注意这里获取的是new InputStreamReader(runProcess.getErrorStream()
                BufferedReader errorBufferedReader = new BufferedReader(new InputStreamReader(runProcess.getErrorStream()));
                List<String> errorOutputStrList = new ArrayList<>();
                // 逐行获取
                String errorCompileOutputLine;
                while((errorCompileOutputLine = errorBufferedReader.readLine()) != null){
                    errorOutputStrList.add(errorCompileOutputLine);
                }
                executeMessage.setErrorMessage(StringUtils.join(errorOutputStrList,"\n"));
            }

            // 获取最终内存使用情况
            long totalMemory = runtime.totalMemory(); // JVM 的总内存量
            long freeMemory = runtime.freeMemory();   // JVM 的空闲内存量
            long usedMemory = (totalMemory - freeMemory)/1024/8; // JVM 已使用的内存量
            executeMessage.setMemory(usedMemory);

            stopWatch.stop();
            executeMessage.setTime(stopWatch.getTotalTimeMillis());
        } catch (IOException | InterruptedException  e ) {
            return getErrorResponse(e);
        }
        return executeMessage;
    }

    /**
     * 获取进程信息（scanner 输入版本）
     * @param runProcess
     * @param opName
     * @return
     */
    public static ExecuteMessage getInterActionProcessMessage(Process runProcess,String opName,String args){
        ExecuteMessage executeMessage = new ExecuteMessage();
        try {
            // 向控制台输入程序
            OutputStream outputStream = runProcess.getOutputStream();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            String[] s = args.split(" ");
            String join = StrUtil.join("\n",s)+"\n";
            outputStreamWriter.write(join);
            // 刷新, 相当于按了回车
            outputStreamWriter.flush();

            // 分批获取进程的输出
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
            List<String> outputStrList = new ArrayList<>();
            // 逐行获取
            String compileOutputLine;
            while((compileOutputLine = bufferedReader.readLine()) != null){
                outputStrList.add(compileOutputLine);
            }
            executeMessage.setMessage(StringUtils.join(outputStrList,"\n"));
            // 关闭资源
            outputStreamWriter.close();
            outputStream.close();
            runProcess.destroy();
        } catch (IOException e) {
            return getErrorResponse(e);
        }
        return executeMessage;
    }

    private static ExecuteMessage getErrorResponse(Throwable e){
        ExecuteMessage executeMessage = new ExecuteMessage();
        executeMessage.setErrorMessage("沙箱错误（编译错误）");
        // 沙箱错误，可能是编译出现错误
        executeMessage.setStatus(2);
        return executeMessage;

    }


    private static long getProcessMemoryUsage() {
        OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        return (long) osBean.getProcessCpuLoad();
    }
}
